import time
import threading, queue
from threading import Thread, Timer
from lib.log import logger


class Task(object):
    id = None
    execute_time = None
    def __init__(self, id) -> None:
        super().__init__()
        self.id = id 
        self.flows = []

    def set_flow(self, cls, form):
        self.flows.append((cls, form))

    def is_now(self):
        if self.execute_time is None:
            return True
        return time.time() > self.execute_time 

    def set_execute_time(self, execute_time):
        self.execute_time = execute_time

    def get_cls(self, cls_name, scripts):
        script = list(filter(lambda x: str(x.name) == cls_name, scripts))[0]
        return script

    def run(self, scripts):
        def run_flow(flow):
            for i in range(0, 5):
                logger.info(f"流程第{i+1}次执行")
                # 第二次重试的时候,入参变成true, 执行的时候就会跳过已经执行成功的记录
                retry = i > 0
                flow.set_retry(retry)
                err_list = flow.run()
                if err_list is None or len(err_list) == 0:
                    logger.info(f"流程第{i+1}次执行完成")
                    return
                logger.info(f"流程第{i+1}次执行完成, 有[{len(err_list)}条]失败记录")

        for cls_name, form in self.flows:
            script = self.get_cls(cls_name, scripts)
            if script.func:
                script.func(**form)
            else:
                flow = script.cls(**form)
                run_flow(flow)

import shelve
import atexit
import os
class TaskScheduler(object):
    taskid = 0
    tasks = queue.Queue()

    def __init__(self, scripts) -> None:
        super().__init__()
        self.scripts = scripts
        tmp_dir = os.path.join(os.getcwd(), ".tmp")
        if not os.path.exists(tmp_dir):
            os.makedirs(tmp_dir)
        db_file = os.path.join(tmp_dir, "task.db")
        self.task_db = shelve.open(db_file)
        self.tasks = queue.Queue()
        if "task" in  self.task_db:
            saved_list = self.task_db["task"]
            logger.info(f"加载保存已保存任务:{len(saved_list)}个")
            for it in saved_list:
                self.tasks.put(it)
        
        def close_db():
            if self.task_db:
                self.task_db.sync()
                self.task_db.close()
        atexit.register(close_db)

        thread = Thread(target=self.run, daemon=True)
        thread.start()

    def submit(self, flow_cls_name, flow_args, execute_time=None):
        logger.info(f"收到任务请求:{flow_cls_name}")
        if execute_time:
            logger.info(f"计划执行时间:{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(execute_time))}")
        else:
            logger.info(f"立即执行")
        self.taskid += 1
        task = Task(id=self.taskid)
        task.set_flow(flow_cls_name, flow_args)
        task.set_execute_time(execute_time)
        self.tasks.put(task)

    def save_tasks(self):
        self.task_db["task"] = list(self.tasks.queue)
        self.task_db.sync()

    def run(self):
        while True:
            try:
                task = self.tasks.get(block=True)
                logger.debug(f"GET TASK:{task.id}")
                if task.is_now():
                    logger.debug(f"RUN TASK:{task.id}")
                    task.run(self.scripts)
                else:
                    logger.debug(f"RETURN TASK:{task.id}")
                    self.tasks.put(task)
                self.tasks.task_done()
                time.sleep(0.1)
                self.save_tasks()
            except Exception as e:
                logger.error(e)


